package com.whmall.service.crm.module.company.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.whmall.common.enumeration.YesNoEnum;
import com.whmall.component.entity.dto.CompanyKeyFieldDTO;
import com.whmall.component.entity.dto.OperatorReqDTO;
import com.whmall.component.enumeration.CompanyLogOperationTypeEnum;
import com.whmall.component.service.AbstractDbService;
import com.whmall.component.util.FieldUtils;
import com.whmall.service.crm.entity.dto.company.CompanyIndustryTypeCreateOrUpdateDTO;
import com.whmall.service.crm.entity.dto.company.CompanyIndustryTypeRspDTO;
import com.whmall.service.crm.entity.dto.company.CompanyTypeRspDTO;
import com.whmall.service.crm.module.company.dao.CompanyIndustryTypeMapper;
import com.whmall.service.crm.module.company.dao.CompanyMapper;
import com.whmall.service.crm.module.company.entity.CompanyIndustryTypeDO;
import com.whmall.service.crm.module.company.entity.CompanyIndustryTypeStrDO;
import com.whmall.service.crm.module.company.entity.CompanyLogDO;
import com.whmall.service.crm.module.company.service.CompanyIndustryTypeService;
import com.whmall.service.crm.module.company.service.CompanyLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;


@Slf4j
@Service
public class CompanyIndustryTypeServiceImpl extends AbstractDbService<CompanyIndustryTypeMapper, CompanyIndustryTypeDO>
        implements CompanyIndustryTypeService {

    @Autowired
    private CompanyMapper companyMapper;

    @Autowired
    private CompanyIndustryTypeMapper companyIndustryTypeMapper;
    @Autowired
    private CompanyLogService companyLogService;
    private final static String KEY = "$dict$company_industry_type";
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private Map<Integer, String> typeMap = new HashMap<>();

    @PostConstruct
    public void init() {
        typeValueMap();
    }

    @Transactional
    @Override
    public void saveOrUpdate(CompanyIndustryTypeCreateOrUpdateDTO createOrUpdateDTO, OperatorReqDTO operatorReqDTO) {

        Assert.isTrue(ObjectUtil.isNotNull(companyMapper.selectById(createOrUpdateDTO.getCompanyId())), "请求参数异常");
        if (CollUtil.isEmpty(createOrUpdateDTO.getTypeList())) {
            return;
        }

        List<CompanyIndustryTypeDO> existList = super.list(Wrappers.<CompanyIndustryTypeDO>lambdaQuery()
                .eq(CompanyIndustryTypeDO::getCompanyId, createOrUpdateDTO.getCompanyId()));

        // 新增的行业类型
        getAddAndSave(createOrUpdateDTO, existList, operatorReqDTO);

        // 删除的行业类型
        getRemoveAndUpdate(createOrUpdateDTO, existList, operatorReqDTO);

        // 变更的行业类型
        getUpdateAndUpdate(createOrUpdateDTO, existList, operatorReqDTO);

    }

    @Override
    public Map<Long, List<CompanyIndustryTypeRspDTO>> getByCompanyIds(List<Long> companyIdList) {

        if (CollectionUtils.isEmpty(companyIdList)) {
            return Collections.emptyMap();
        }
        List<CompanyIndustryTypeDO> list = super.list(Wrappers.<CompanyIndustryTypeDO>lambdaQuery()
                .in(CompanyIndustryTypeDO::getCompanyId, companyIdList)
                .eq(CompanyIndustryTypeDO::getIsDeleted, YesNoEnum.NO.getCode()));

        if (CollUtil.isEmpty(list)) {
            return MapUtil.empty();
        }

        Map<Long, List<CompanyIndustryTypeDO>> groupMap = list.stream()
                .collect(Collectors.groupingBy(CompanyIndustryTypeDO::getCompanyId));

        Map<Long, List<CompanyIndustryTypeRspDTO>> result = new HashMap<>();

        groupMap.forEach((k, v) -> {
            result.put(k, v.stream()
                    .map(value -> {
                        CompanyIndustryTypeRspDTO rspDTO = new CompanyIndustryTypeRspDTO();
                        BeanUtils.copyProperties(value, rspDTO);
                        return rspDTO;
                    }).collect(Collectors.toList()));
        });

        return result;
    }

    @Override
    public Map<Long, CompanyTypeRspDTO> getTypesByCompanyIds(List<Long> companyIdList) {

        Map<Long, CompanyTypeRspDTO> resultMap = new HashMap<>();

        Map<Long, List<CompanyIndustryTypeRspDTO>> map = getByCompanyIds(companyIdList);

        if (map.keySet().stream().noneMatch(k -> companyIdList.contains(k))) {
            companyIdList.stream()
                    .filter(c -> !map.keySet().contains(c))
                    .forEach(c -> {
                        CompanyTypeRspDTO companyTypeRspDTO = new CompanyTypeRspDTO();
                        companyTypeRspDTO.setCompanyId(c);
                        companyTypeRspDTO.setCompanyType("");
                        companyTypeRspDTO.setCompanyTypeList(Collections.emptyList());
                        resultMap.put(c, companyTypeRspDTO);
                    });
        }

        if (MapUtil.isNotEmpty(map)) {
            map.entrySet().forEach(entry -> {
                CompanyTypeRspDTO companyTypeRspDTO = new CompanyTypeRspDTO();
                companyTypeRspDTO.setCompanyId(entry.getKey());
                companyTypeRspDTO.setCompanyTypeList(entry.getValue().stream().map(t -> {
                    CompanyKeyFieldDTO.Type type = new CompanyKeyFieldDTO.Type();
                    type.setFirstType(t.getFirstType());
                    type.setSecondTypeList(FieldUtils.unwrapArray(t.getSecondType(), "-", Integer.class));
                    return type;
                }).collect(Collectors.toList()));
                List<Integer> typeList = new ArrayList<>();
                if (CollUtil.isNotEmpty(companyTypeRspDTO.getCompanyTypeList())) {
                    companyTypeRspDTO.getCompanyTypeList().forEach(t -> {
                        typeList.add(t.getFirstType());
                        if (CollUtil.isNotEmpty(t.getSecondTypeList())) {
                            typeList.addAll(t.getSecondTypeList());
                        }
                    });
                }
                companyTypeRspDTO.setCompanyType(CollUtil.isNotEmpty(typeList) ? FieldUtils.wrapArray(typeList, "-", true) : "");
                resultMap.put(entry.getKey(), companyTypeRspDTO);
            });
        }

        return resultMap;
    }

    @Override
    public Map<Long, String> getTypeStrByCompanyIds(List<Long> companyIdList) {
        Map<Long, String> map = super.baseMapper.getCompanyTypeMap(companyIdList)
                .stream()
                .collect(Collectors.toMap(CompanyIndustryTypeStrDO::getCompanyId, e -> e.getType()));

        return null != map ? map : MapUtil.empty();
    }

    /**
     * 获取新增的行业类型并保存
     *
     * @param createOrUpdateDTO
     * @param existList
     * @param operatorReqDTO
     */
    private void getAddAndSave(CompanyIndustryTypeCreateOrUpdateDTO createOrUpdateDTO,
                               List<CompanyIndustryTypeDO> existList,
                               OperatorReqDTO operatorReqDTO) {

        List<CompanyKeyFieldDTO.Type> addTypeList = createOrUpdateDTO.getTypeList()
                .stream()
                .filter(t -> existList.stream().noneMatch(e -> e.getFirstType().equals(t.getFirstType())))
                .collect(Collectors.toList());

        if (CollUtil.isNotEmpty(addTypeList)) {
            super.saveBatch(addTypeList.stream()
                    .map(a -> {
                        CompanyIndustryTypeDO companyIndustryTypeDO = new CompanyIndustryTypeDO();
                        companyIndustryTypeDO.setCompanyId(createOrUpdateDTO.getCompanyId());
                        companyIndustryTypeDO.setFirstType(a.getFirstType());
                        companyIndustryTypeDO.setCreateId(operatorReqDTO.getOperatorId());
                        companyIndustryTypeDO.setCreateTime(new Date());
                        if (CollUtil.isNotEmpty(a.getSecondTypeList())) {
                            companyIndustryTypeDO.setSecondType(FieldUtils.wrapArray(a.getSecondTypeList(), "-", true));
                        } else {
                            companyIndustryTypeDO.setSecondType("");
                        }
                        return companyIndustryTypeDO;
                    }).collect(Collectors.toList()));
        }

        if (null == typeMap) {
            typeValueMap();
        }

        // 公司日志
        companyLogService.saveBatch(addTypeList.stream().map(a -> {
            CompanyLogDO companyLogDO = makeCompanyLog(createOrUpdateDTO, operatorReqDTO);
            companyLogDO.setOperationDesc1("新增公司业务性质，新增行业类型为：\"" + typeMap.get(a.getFirstType()) + (CollUtil.isEmpty(a.getSecondTypeList()) ? "\"" :
                    "\"行业细分为：\"" + a.getSecondTypeList().stream().map(s -> typeMap.get(s)).collect(Collectors.joining(",")) + "\""));
            return companyLogDO;
        }).collect(Collectors.toList()));
    }

    /**
     * 获取删除的行业类型并更新
     *
     * @param createOrUpdateDTO
     * @param existList
     * @param operatorReqDTO
     */
    private void getRemoveAndUpdate(CompanyIndustryTypeCreateOrUpdateDTO createOrUpdateDTO,
                                    List<CompanyIndustryTypeDO> existList,
                                    OperatorReqDTO operatorReqDTO) {

        List<CompanyIndustryTypeDO> delList = existList.stream()
                .filter(e -> e.getIsDeleted() == 0
                        && createOrUpdateDTO.getTypeList().stream().noneMatch(c -> c.getFirstType().equals(e.getFirstType())))
                .collect(Collectors.toList());

        if (CollUtil.isNotEmpty(delList)) {
            super.updateBatchById(delList.stream()
                    .map(d -> {
                        CompanyIndustryTypeDO companyIndustryTypeDO = new CompanyIndustryTypeDO();
                        companyIndustryTypeDO.setId(d.getId());
                        companyIndustryTypeDO.setIsDeleted(YesNoEnum.YES.getCode());
                        companyIndustryTypeDO.setUpdateId(operatorReqDTO.getOperatorId());
                        companyIndustryTypeDO.setUpdateTime(new Date());
                        return companyIndustryTypeDO;
                    }).collect(Collectors.toList()));
        }

        if (null == typeMap) {
            typeValueMap();
        }

        // 公司日志
        companyLogService.saveBatch(delList.stream().map(a -> {
            CompanyLogDO companyLogDO = makeCompanyLog(createOrUpdateDTO, operatorReqDTO);
            companyLogDO.setOperationDesc1("删除公司业务性质，删除行业类型为：\"" + typeMap.get(a.getFirstType()) + (StringUtils.hasText(a.getSecondType()) ?
                    "\"行业细分为：\"" + FieldUtils.unwrapArray(a.getSecondType(), "-", Integer.class)
                            .stream()
                            .map(s -> typeMap.get(s))
                            .collect(Collectors.joining(",")) + "\"" : "\""));
            return companyLogDO;
        }).collect(Collectors.toList()));
    }

    /**
     * 获取更新的行业类型并更新
     *
     * @param createOrUpdateDTO
     * @param existList
     * @param operatorReqDTO
     */
    private void getUpdateAndUpdate(CompanyIndustryTypeCreateOrUpdateDTO createOrUpdateDTO,
                                    List<CompanyIndustryTypeDO> existList,
                                    OperatorReqDTO operatorReqDTO) {

        List<CompanyIndustryTypeDO> updateTypeList = existList
                .stream()
                .filter(t -> createOrUpdateDTO.getTypeList().stream().anyMatch(e -> e.getFirstType().equals(t.getFirstType())))
                .collect(Collectors.toList());

        AtomicBoolean changed = new AtomicBoolean(false);
        if (CollUtil.isNotEmpty(updateTypeList)) {
            super.updateBatchById(updateTypeList.stream()
                    .map(u -> {
                        CompanyIndustryTypeDO companyIndustryTypeDO = new CompanyIndustryTypeDO();
                        companyIndustryTypeDO.setId(u.getId());
                        companyIndustryTypeDO.setIsDeleted(YesNoEnum.NO.getCode());
                        companyIndustryTypeDO.setUpdateId(operatorReqDTO.getOperatorId());
                        companyIndustryTypeDO.setUpdateTime(new Date());
                        CompanyKeyFieldDTO.Type type = createOrUpdateDTO.getTypeList().stream().filter(c -> c.getFirstType().equals(u.getFirstType())).findFirst().get();

                        if (CollUtil.isNotEmpty(type.getSecondTypeList())) {
                            companyIndustryTypeDO.setSecondType(FieldUtils.wrapArray(type.getSecondTypeList(), "-", true));
                        } else {
                            companyIndustryTypeDO.setSecondType("");
                        }

                        if (!u.getSecondType().equals(companyIndustryTypeDO.getSecondType())) {
                            changed.set(true);
                        }

                        return companyIndustryTypeDO;
                    }).collect(Collectors.toList()));
        }

        if (null == typeMap) {
            typeValueMap();
        }

        // 公司日志
        if (changed.get()) {
            companyLogService.saveBatch(updateTypeList.stream().map(a -> {
                CompanyLogDO companyLogDO = makeCompanyLog(createOrUpdateDTO, operatorReqDTO);

                List<Integer> secondList = createOrUpdateDTO.getTypeList().stream()
                        .filter(c -> c.getFirstType().equals(a.getFirstType()))
                        .findFirst()
                        .get()
                        .getSecondTypeList();

                companyLogDO.setOperationDesc1("更新公司业务性质，更新行业类型：\"" +
                        typeMap.get(a.getFirstType()) + (CollUtil.isEmpty(secondList) ? "\"" :
                        "\"的行业细分为：\"" + secondList.stream().map(s -> typeMap.get(s)).collect(Collectors.joining(",")) + "\""));
                return companyLogDO;
            }).collect(Collectors.toList()));
        }
    }

    /**
     * 组装公司日志
     *
     * @param createOrUpdateDTO
     * @param operatorReqDTO
     * @return
     */
    private CompanyLogDO makeCompanyLog(CompanyIndustryTypeCreateOrUpdateDTO createOrUpdateDTO, OperatorReqDTO operatorReqDTO) {
        CompanyLogDO companyLogDO = new CompanyLogDO();
        companyLogDO.setCompanyId(createOrUpdateDTO.getCompanyId());
        companyLogDO.setCreateId(operatorReqDTO.getOperatorId());
        companyLogDO.setIp(operatorReqDTO.getIp());
        companyLogDO.setCreateTime(new Date());
        companyLogDO.setCreateType(operatorReqDTO.getOperatorType().getValue());
        companyLogDO.setOperationType(CompanyLogOperationTypeEnum.COMPANY_TYPE_CHANGE.getValue());
        return companyLogDO;
    }

    /**
     * 获取对应值描述
     *
     * @return
     */
    private void typeValueMap() {
        typeMap.clear();
        Map<Object, Object> map = redisTemplate.opsForHash().entries(KEY);
        map.forEach((k, v) -> {
            JsonObject jsonObject = (JsonObject) JsonParser.parseString((String) v);
            typeMap.put(Integer.valueOf((String) k), jsonObject.get("name").getAsString());
        });
    }

    @Override
    public Boolean selectByIdsShareLock(List<Long> ids) {
        return CollUtil.isNotEmpty(super.baseMapper.selectByIdsShareLock(ids));
    }
}
